package core

import (
	"bytes"
	"encoding/binary"
	"errors"
	"os"
	"path/filepath"
	"runtime"
)

const (
	MQ_Connect       = byte(0x10)
	MQ_ConnectAck    = byte(0x20)
	MQ_Pub           = byte(0x30) //客户端或服务端发布消息的核心报文，携带主题、QoS等级、消息标识符（QoS>0时）和负载
	MQ_FinishAck     = byte(0x31)
	MQ_PubAck        = byte(0x40) //QoS 1的确认响应，表示服务器已成功接收PUBLISH消息
	MQ_PubRec        = byte(0x50) //QoS 2的第一阶段确认，接收方发送此报文表示已收到PUBLISH消息
	MQ_PubRel        = byte(0x60) //QoS 2的第二阶段响应，发送方释放消息资源
	MQ_PubComp       = byte(0x70) //QoS 2的最终确认，表示消息传输完成
	MQ_Sub           = byte(0x80)
	MQ_SubAck        = byte(0x90)
	MQ_UnSub         = byte(0xa0)
	MQ_UnSubAck      = byte(0xb0)
	MQ_HeartBeat     = byte(0xc0)
	MQ_HeartBeatResp = byte(0xd0)
	MQ_DisConnect    = byte(0xe0)
	MQ_P2P           = byte(0xf0)
	MQ_P2PAck        = byte(0xf1)

	MQ_QOS_0 = byte(0x00) //最多一次，消息发送不确认，可能丢失
	MQ_QOS_1 = byte(0x01) // 至少一次，消息发送确认，可能重复
	MQ_QOS_2 = byte(0x02) // 恰好一次，消息发送4次握手确认，保证不重复，有且只接收一次

	MQ_OverTime = 3000 //消息消费时长(单位为毫秒)，如果超过该时长，则消息被收回，再次分配

	MQ_Topic_All = uint8(0x00) //普通主题类型
	MQ_Topic_One = uint8(0x01) //负载均衡类型，只能选一个消费者

	MQ_OnlyOneUse = uint8(0x01)
)

type Count struct {
	ClientCount  uint32 //客户端数量
	PackageCount uint64
	PackageSize  uint64
}

var count_instance *Count = nil

func GetCount() *Count {
	if count_instance == nil {
		count_instance = &Count{ClientCount: 0, PackageCount: 0, PackageSize: 0}
	}
	return count_instance
}

func GetResourcesDir() (string, error) {
	if runtime.GOOS != "darwin" {
		return "", nil
	}

	// 获取当前可执行文件路径
	execPath, err := os.Executable()
	if err != nil {
		return "", err
	}

	// 应用打包后，资源目录通常在：App.app/Contents/Resources/
	// 从可执行文件路径逆向推导（可执行文件在 App.app/Contents/MacOS/ 下）
	resourcesDir := filepath.Join(filepath.Dir(execPath), "..", "Resources")

	// 转换为绝对路径
	return filepath.Abs(resourcesDir)
}

// /////////////////////////////////////////////////////////////////////
type HeartBeatMsg struct {
	HeartBeatTime uint64 // 心跳时间戳
	ClientID      uint64 // 客户端ID
}

func DecodeHeartBeatMsg(data []byte) (*HeartBeatMsg, error) {
	if len(data) < 8 {
		return nil, errors.New("data too short to decode HeartBeatMsg")
	}
	if data[0] != MQ_HeartBeat {
		return nil, errors.New("invalid message type")
	}
	heartBeatTime := binary.BigEndian.Uint64(data[1:9])
	clientID, err := ReadUint64FromBytes(data[9:])
	if err != nil {
		return nil, err
	}
	return &HeartBeatMsg{
		HeartBeatTime: heartBeatTime,
		ClientID:      clientID,
	}, nil
}

func EncodeHeartBeatMsg(msg *HeartBeatMsg) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)

	if err := bufs.WriteByte(MQ_HeartBeat); err != nil {
		return nil, err
	}

	if err := binary.Write(bufs, binary.BigEndian, msg.HeartBeatTime); err != nil {
		return nil, err
	}

	if _, err := WriteUint64(bufs, msg.ClientID); err != nil {
		return nil, err
	}

	return bufs.Bytes(), nil
}

// ///////////////////////////////////////////////////////////////
type ConnectMsg struct {
	UserID   uint64 // 客户端ID,具有唯一性
	Password string
}

func NewConnectMsg(clientID uint64, password string) *ConnectMsg {
	return &ConnectMsg{UserID: clientID, Password: password}
}

func DecodeConnectMsg(data []byte) (*ConnectMsg, error) {
	if data[0] != MQ_Connect {
		return nil, errors.New("invalid message type")
	}
	clientID, err := ReadUint64FromBytes(data[1:])
	if err != nil {
		return nil, err
	}

	password, err := ReadStringFromBytes(data[9:])
	if err != nil {
		return nil, err
	}
	return &ConnectMsg{
		UserID:   clientID,
		Password: password,
	}, nil

}

func EncodeConnectMsg(msg *ConnectMsg) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)

	if err := bufs.WriteByte(MQ_Connect); err != nil {
		return nil, err
	}

	if _, err := WriteUint64(bufs, msg.UserID); err != nil {
		return nil, err
	}

	if _, err := WriteString(bufs, msg.Password); err != nil {
		return nil, err
	}
	return bufs.Bytes(), nil
}

// //////////////////////////////////////////////////////////////////
type ConnectAckMsg struct {
	UserID   uint64
	UserName string
	Result   uint8 // 0: success, 1: failure
	Error    error
	AES128   string
}

func EncodeConnectAckMsg(msg *ConnectAckMsg) ([]byte, error) {
	bufs := bytes.NewBuffer(nil)

	if err := bufs.WriteByte(MQ_ConnectAck); err != nil {
		return nil, err
	}
	if _, err := WriteUint64(bufs, msg.UserID); err != nil {
		return nil, err
	}
	if _, err := WriteString(bufs, msg.UserName); err != nil {
		return nil, err
	}
	if err := bufs.WriteByte(msg.Result); err != nil {
		return nil, err
	}

	if msg.Error != nil {
		if _, err := WriteString(bufs, msg.Error.Error()); err != nil {
			return nil, err
		}
	} else {
		if _, err := WriteUint32(bufs, 0); err != nil {
			return nil, err
		}
	}
	if _, err := WriteString(bufs, msg.AES128); err != nil {
		return nil, err
	}

	return bufs.Bytes(), nil
}

// func DecodeConnectAckMsg(data []byte) (*ConnectAckMsg, error) {
// 	if len(data) < 5 {
// 		return nil, errors.New("data too short to decode ConnectAckMsg")
// 	}
// 	if data[0] != MQ_ConnectAck {
// 		return nil, errors.New("invalid message type")
// 	}
// 	result := data[1]
// 	var err error
// 	if len(data) > 2 {
// 		errMsg, err1 := ReadStringFromBytes(data[2:])
// 		if err1 != nil {
// 			return nil, err
// 		}
// 		err = errors.New(errMsg)
// 	} else {
// 		err = nil
// 	}
// 	return &ConnectAckMsg{
// 		Result: result,
// 		Error:  err,
// 	}, nil
// }
